text:
/* cpu_x86.cpp
 *
 * Author           : Alexander J. Yee
 * Date Created     : 04/12/2014
 * Last Modified    : 04/12/2014
 *
 */

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//  Dependencies
#include <cstring>
#include <iostream>
#include "cpu_x86.h"
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#if defined(__x86_64__) || defined(_M_X64) || defined(__i386) || defined(_M_IX86)
#   if _WIN32
#       include "cpu_x86_Windows.ipp"
#   elif defined(__GNUC__) || defined(__clang__)
#       include "cpu_x86_Linux.ipp"
#   else
#       error "No cpuid intrinsic defined for compiler."
#   endif
#else
#   error "No cpuid intrinsic defined for processor architecture."
#endif

namespace FeatureDetector{
    using std::cout;
    using std::endl;
    using std::memcpy;
    using std::memset;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void cpu_x86::print(const char* label, bool yes){
    cout << label;
    cout << (yes ? "Yes" : "No") << endl;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
cpu_x86::cpu_x86(){
    memset(this, 0, sizeof(*this));
}
bool cpu_x86::detect_OS_AVX(){
    //  Copied from: http://stackoverflow.com/a/22521619/922184

    bool avxSupported = false;

    int32_t cpuInfo[4];
    cpuid(cpuInfo, 1, 0);

    bool osUsesXSAVE_XRSTORE = (cpuInfo[2] & (1 << 27)) != 0;
    bool cpuAVXSuport = (cpuInfo[2] & (1 << 28)) != 0;

    if (osUsesXSAVE_XRSTORE && cpuAVXSuport)
    {
        uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK);
        avxSupported = (xcrFeatureMask & 0x6) == 0x6;
    }

    return avxSupported;
}
bool cpu_x86::detect_OS_AVX512(){
    if (!detect_OS_AVX())
        return false;

    uint64_t xcrFeatureMask = xgetbv(_XCR_XFEATURE_ENABLED_MASK);
    return (xcrFeatureMask & 0xe6) == 0xe6;
}
std::string cpu_x86::get_vendor_string(){
    int32_t CPUInfo[4];
    char name[13];

    cpuid(CPUInfo, 0, 0);
    memcpy(name + 0, &CPUInfo[1], 4);
    memcpy(name + 4, &CPUInfo[3], 4);
    memcpy(name + 8, &CPUInfo[2], 4);
    name[12] = '\0';

    return name;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void cpu_x86::detect_host(){
    //  OS Features
    OS_x64 = detect_OS_x64();
    OS_AVX = detect_OS_AVX();
    OS_AVX512 = detect_OS_AVX512();

    //  Vendor
    std::string vendor(get_vendor_string());
    if (vendor == "GenuineIntel"){
        Vendor_Intel = true;
    }else if (vendor == "AuthenticAMD"){
        Vendor_AMD = true;
    }

    int32_t info[4];
    cpuid(info, 0, 0);
    int nIds = info[0];

    cpuid(info, 0x80000000, 0);
    uint32_t nExIds = info[0];

    //  Detect Features
    if (nIds >= 0x00000001){
        cpuid(info, 0x00000001, 0);
        HW_MMX    = (info[3] & ((int)1 << 23)) != 0;
        HW_SSE    = (info[3] & ((int)1 << 25)) != 0;
        HW_SSE2   = (info[3] & ((int)1 << 26)) != 0;
        HW_SSE3   = (info[2] & ((int)1 <<  0)) != 0;

        HW_SSSE3  = (info[2] & ((int)1 <<  9)) != 0;
        HW_SSE41  = (info[2] & ((int)1 << 19)) != 0;
        HW_SSE42  = (info[2] & ((int)1 << 20)) != 0;
        HW_AES    = (info[2] & ((int)1 << 25)) != 0;

        HW_AVX    = (info[2] & ((int)1 << 28)) != 0;
        HW_FMA3   = (info[2] & ((int)1 << 12)) != 0;

        HW_RDRAND = (info[2] & ((int)1 << 30)) != 0;
    }
    if (nIds >= 0x00000007){
        cpuid(info, 0x00000007, 0);
        HW_AVX2         = (info[1] & ((int)1 <<  5)) != 0;

        HW_BMI1         = (info[1] & ((int)1 <<  3)) != 0;
        HW_BMI2         = (info[1] & ((int)1 <<  8)) != 0;
        HW_ADX          = (info[1] & ((int)1 << 19)) != 0;
        HW_MPX          = (info[1] & ((int)1 << 14)) != 0;
        HW_SHA          = (info[1] & ((int)1 << 29)) != 0;
        HW_RDSEED       = (info[1] & ((int)1 << 18)) != 0;
        HW_PREFETCHWT1  = (info[2] & ((int)1 <<  0)) != 0;
        HW_RDPID        = (info[2] & ((int)1 << 22)) != 0;

        HW_AVX512_F     = (info[1] & ((int)1 << 16)) != 0;
        HW_AVX512_CD    = (info[1] & ((int)1 << 28)) != 0;
        HW_AVX512_PF    = (info[1] & ((int)1 << 26)) != 0;
        HW_AVX512_ER    = (info[1] & ((int)1 << 27)) != 0;

        HW_AVX512_VL    = (info[1] & ((int)1 << 31)) != 0;
        HW_AVX512_BW    = (info[1] & ((int)1 << 30)) != 0;
        HW_AVX512_DQ    = (info[1] & ((int)1 << 17)) != 0;

        HW_AVX512_IFMA  = (info[1] & ((int)1 << 21)) != 0;
        HW_AVX512_VBMI  = (info[2] & ((int)1 <<  1)) != 0;

        HW_AVX512_VPOPCNTDQ = (info[2] & ((int)1 << 14)) != 0;
        HW_AVX512_4VNNIW    = (info[3] & ((int)1 <<  2)) != 0;
        HW_AVX512_4FMAPS    = (info[3] & ((int)1 <<  3)) != 0;

        HW_AVX512_VNNI      = (info[2] & ((int)1 << 11)) != 0;

        HW_AVX512_VBMI2     = (info[2] & ((int)1 <<  6)) != 0;
        HW_GFNI             = (info[2] & ((int)1 <<  8)) != 0;
        HW_VAES             = (info[2] & ((int)1 <<  9)) != 0;
        HW_AVX512_VPCLMUL   = (info[2] & ((int)1 << 10)) != 0;
        HW_AVX512_BITALG    = (info[2] & ((int)1 << 12)) != 0;

        cpuid(info, 0x00000007, 1);
        HW_AVX512_BF16      = (info[0] & ((int)1 <<  5)) != 0;
    }
    if (nExIds >= 0x80000001){
        cpuid(info, 0x80000001, 0);
        HW_x64   = (info[3] & ((int)1 << 29)) != 0;
        HW_ABM   = (info[2] & ((int)1 <<  5)) != 0;
        HW_SSE4a = (info[2] & ((int)1 <<  6)) != 0;
        HW_FMA4  = (info[2] & ((int)1 << 16)) != 0;
        HW_XOP   = (info[2] & ((int)1 << 11)) != 0;
        HW_PREFETCHW = (info[2] & ((int)1 << 8)) != 0;
    }
}
void cpu_x86::print() const{
    cout << "CPU Vendor:" << endl;
    print("    AMD         = ", Vendor_AMD);
    print("    Intel       = ", Vendor_Intel);
    cout << endl;

    cout << "OS Features:" << endl;
#ifdef _WIN32
    print("    64-bit      = ", OS_x64);
#endif
    print("    OS AVX      = ", OS_AVX);
    print("    OS AVX512   = ", OS_AVX512);
    cout << endl;

    cout << "Hardware Features:" << endl;
    print("    MMX         = ", HW_MMX);
    print("    x64         = ", HW_x64);
    print("    ABM         = ", HW_ABM);
    print("    RDRAND      = ", HW_RDRAND);
    print("    RDSEED      = ", HW_RDSEED);
    print("    BMI1        = ", HW_BMI1);
    print("    BMI2        = ", HW_BMI2);
    print("    ADX         = ", HW_ADX);
    print("    MPX         = ", HW_MPX);
    print("    PREFETCHW   = ", HW_PREFETCHW);
    print("    PREFETCHWT1 = ", HW_PREFETCHWT1);
    print("    RDPID       = ", HW_RDPID);
    print("    GFNI        = ", HW_GFNI);
    print("    VAES        = ", HW_VAES);
    cout << endl;

    cout << "SIMD: 128-bit" << endl;
    print("    SSE         = ", HW_SSE);
    print("    SSE2        = ", HW_SSE2);
    print("    SSE3        = ", HW_SSE3);
    print("    SSSE3       = ", HW_SSSE3);
    print("    SSE4a       = ", HW_SSE4a);
    print("    SSE4.1      = ", HW_SSE41);
    print("    SSE4.2      = ", HW_SSE42);
    print("    AES-NI      = ", HW_AES);
    print("    SHA         = ", HW_SHA);
    cout << endl;

    cout << "SIMD: 256-bit" << endl;
    print("    AVX         = ", HW_AVX);
    print("    XOP         = ", HW_XOP);
    print("    FMA3        = ", HW_FMA3);
    print("    FMA4        = ", HW_FMA4);
    print("    AVX2        = ", HW_AVX2);
    cout << endl;

    cout << "SIMD: 512-bit" << endl;
    print("    AVX512-F         = ", HW_AVX512_F);
    print("    AVX512-CD        = ", HW_AVX512_CD);
    print("    AVX512-PF        = ", HW_AVX512_PF);
    print("    AVX512-ER        = ", HW_AVX512_ER);
    print("    AVX512-VL        = ", HW_AVX512_VL);
    print("    AVX512-BW        = ", HW_AVX512_BW);
    print("    AVX512-DQ        = ", HW_AVX512_DQ);
    print("    AVX512-IFMA      = ", HW_AVX512_IFMA);
    print("    AVX512-VBMI      = ", HW_AVX512_VBMI);
    print("    AVX512-VPOPCNTDQ = ", HW_AVX512_VPOPCNTDQ);
    print("    AVX512-4VNNIW    = ", HW_AVX512_4VNNIW);
    print("    AVX512-4FMAPS    = ", HW_AVX512_4FMAPS);
    print("    AVX512-VBMI2     = ", HW_AVX512_VBMI2);
    print("    AVX512-VPCLMUL   = ", HW_AVX512_VPCLMUL);
    print("    AVX512-VNNI      = ", HW_AVX512_VNNI);
    print("    AVX512-BITALG    = ", HW_AVX512_BITALG);
    print("    AVX512-BF16      = ", HW_AVX512_BF16);
    cout << endl;

    cout << "Summary:" << endl;
    print("    Safe to use AVX:     ", HW_AVX && OS_AVX);
    print("    Safe to use AVX512:  ", HW_AVX512_F && OS_AVX512);
    cout << endl;
}
void cpu_x86::print_host(){
    cpu_x86 features;
    features.detect_host();
    features.print();
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
}


text:
/* cpu_x86_Windows.ipp
 *
 * Author           : Alexander J. Yee
 * Date Created     : 04/12/2014
 * Last Modified    : 04/12/2014
 *
 */

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//  Dependencies
#include <Windows.h>
#include <intrin.h>
#include "cpu_x86.h"
namespace FeatureDetector{
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void cpu_x86::cpuid(int32_t out[4], int32_t eax, int32_t ecx){
    __cpuidex(out, eax, ecx);
}
__int64 xgetbv(unsigned int x){
    return _xgetbv(x);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
//  Detect 64-bit - Note that this snippet of code for detecting 64-bit has been copied from MSDN.
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
BOOL IsWow64()
{
    BOOL bIsWow64 = FALSE;

    LPFN_ISWOW64PROCESS fnIsWow64Process = (LPFN_ISWOW64PROCESS) GetProcAddress(
        GetModuleHandle(TEXT("kernel32")), "IsWow64Process");

    if (NULL != fnIsWow64Process)
    {
        if (!fnIsWow64Process(GetCurrentProcess(), &bIsWow64))
        {
            printf("Error Detecting Operating System.\n");
            printf("Defaulting to 32-bit OS.\n\n");
            bIsWow64 = FALSE;
        }
    }
    return bIsWow64;
}
bool cpu_x86::detect_OS_x64(){
#ifdef _M_X64
    return true;
#else
    return IsWow64() != 0;
#endif
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
}

repo_name: Mysticial/FeatureDetector

mime_type: text/xml


text: add_library(FeatureDetector cpu_x86.cpp cpu_x86.h cpu_x86_Linux.ipp cpu_x86_Windows.ipp)


text:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="..\src\x86\cpu_x86.h" />
  </ItemGroup>
  <ItemGroup>
    <None Include="..\src\x86\cpu_x86_Linux.ipp" />
    <None Include="..\src\x86\cpu_x86_Windows.ipp" />
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="..\src\Main.cpp" />
    <ClCompile Include="..\src\x86\cpu_x86.cpp" />
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <ProjectGuid>{5AF4062D-386F-48AA-B824-2C10A4B1BA97}</ProjectGuid>
    <Keyword>Win32Proj</Keyword>
    <RootNamespace>FeatureDetector</RootNamespace>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v142</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LinkIncremental>true</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>Disabled</Optimization>
      <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <SDLCheck>true</SDLCheck>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <Optimization>MaxSpeed</Optimization>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <SDLCheck>true</SDLCheck>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
    </Link>
  </ItemDefinitionGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>


text:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup />
</Project>


text:
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup>
    <Filter Include="Source Files">
      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
    </Filter>
    <Filter Include="Header Files">
      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
    </Filter>
    <Filter Include="Resource Files">
      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
    </Filter>
    <Filter Include="Header Files\x86">
      <UniqueIdentifier>{7fdc0f8e-15b1-4062-a100-fb566c7e9c8a}</UniqueIdentifier>
    </Filter>
  </ItemGroup>
  <ItemGroup>
    <None Include="..\src\x86\cpu_x86_Windows.ipp">
      <Filter>Header Files\x86</Filter>
    </None>
    <None Include="..\src\x86\cpu_x86_Linux.ipp">
      <Filter>Header Files\x86</Filter>
    </None>
  </ItemGroup>
  <ItemGroup>
    <ClCompile Include="..\src\Main.cpp">
      <Filter>Source Files</Filter>
    </ClCompile>
    <ClCompile Include="..\src\x86\cpu_x86.cpp">
      <Filter>Header Files\x86</Filter>
    </ClCompile>
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="..\src\x86\cpu_x86.h">
      <Filter>Header Files\x86</Filter>
    </ClInclude>
  </ItemGroup>
</Project>


text:
## Contributor License Agreement
By contributing you agree to the [LICENSE](https://github.com/simonebrunozzi/open-guide-to-learning-tech-geek-nerdy-stuff/blob/master/LICENSE) of this repository.

## Contributor Code of Conduct
By contributing you agree to respect the [Code of Conduct](https://github.com/simonebrunozzi/open-guide-to-learning-tech-geek-nerdy-stuff/blob/master/CODE-OF-CONDUCT.md) of this repository.

## Information on how to contribute
We prefer free material, although there might be non-free material that is so good that we still want to include it in here.

The principles behind adding a new link (or a new category) are the following:

1. You can propose a new category if it belongs to the same tech/geek/nerd stuff.

2. You can propose a new "link", by actually simply adding

```
[$succint_description]($link)
```

Example:

```
[Video games and AI](http://togelius.blogspot.com/2016/01/why-video-games-are-essential-for.html)
```

If your link points to a discussion, which then points to the actual resource, such as in the case of a Hacker News discussion, you can simply write:

```
[$succint_description]($link-to-resource) ([HN discussion]($link-to-discussion))
```

Example:

```
[Berkeley AI Materials](http://ai.berkeley.edu/project_overview.html) ([HN discussion](https://news.ycombinator.com/item?id=10929985))
```

If you want to specify the file format (e.g. PDF), you can add it after the `$succint_description`.

## Editing/formatting Guidelines
- We typically don't like files hosted on "temporary" locations, e.g. google drive, dropbox, mega, etc.
- We always prefer a `https` link over a `http` one -- as long as they are on the same domain and serve the same content
- On root domains, strip the trailing slash: use `http://example.com` instead of `http://example.com/`
- Always prefer the shortest link: `http://example.com/dir/` is better than `http://example.com/dir/index.html`
- Do not include URL shortener links
- Most files are `.md` files. Try to learn [Markdown](https://guides.github.com/features/mastering-markdown/) to be a more effective contributor.

mime_type: text/plain


text:
# Contributor Code of Conduct

As contributors and maintainers of this project, and in the interest of
fostering an open and welcoming community, we pledge to respect all people who
contribute through reporting issues, posting feature requests, updating
documentation, submitting pull requests or patches, and other activities.

We are committed to making participation in this project a harassment-free
experience for everyone, regardless of level of experience, gender, gender
identity and expression, sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, religion, or nationality.

Examples of unacceptable behavior by participants include:

* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information, such as physical or electronic
  addresses, without explicit permission
* Other unethical or unprofessional conduct

Project maintainers have the right and responsibility to remove, edit, or
reject comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct, or to ban temporarily or
permanently any contributor for other behaviors that they deem inappropriate,
threatening, offensive, or harmful.

By adopting this Code of Conduct, project maintainers commit themselves to
fairly and consistently applying these principles to every aspect of managing
this project. Project maintainers who do not follow or enforce the Code of
Conduct may be permanently removed from the project team.

This code of conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.

Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported by contacting a project maintainer at victorfelder at gmail.com. All
complaints will be reviewed and investigated and will result in a response that
is deemed necessary and appropriate to the circumstances. Maintainers are
obligated to maintain confidentiality with regard to the reporter of an
incident.

This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 1.3.0, available at
[http://contributor-covenant.org/version/1/3/0/][version]

[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/3/0/


text:
# Open Guide To Learning Tech/Geek/Nerdy Stuff
A list of resources to learn tech/geek/nerdy related topics, e.g. programming languages, android development, math, korean language and the like.

## Introduction

Over time I've built a decent list of links to web resources which contain good material to learn stuff.

What stuff? "Tech" stuff (like Python, BSD, Vim, Security, Javascript, Unix), or other geeky/nerdy stuff (math, how to learn the Korean language, Philosophy, etc).

Two quick examples of how one of these entries look like:

```
BSD: https://hardenedbsd.org/
```

```
Learn Korean: https://news.ycombinator.com/item?id=9935042
```

To avoid confusion, links are grouped into categories.

### Making this list publicly available, and letting everyone collaborate
I think it is valuable to make this list available to everyone, and most importantly, open to anyone's contribution.
If you know how to use Github, it should be easy for you to add your own links.
Over time, my hope is that these contribution will make this list of resources very useful as a good "filter" to find just the good stuff.

Want to contribute? [Go here to read how to](https://github.com/simonebrunozzi/open-guide-to-learning-tech-geek-nerdy-stuff/blob/master/CONTRIBUTING.md), and make sure you respect the [code of conduct](https://github.com/simonebrunozzi/open-guide-to-learning-tech-geek-nerdy-stuff/blob/master/CODE-OF-CONDUCT.md).

Any contribution will be released under the same [license](https://github.com/simonebrunozzi/open-guide-to-learning-tech-geek-nerdy-stuff/blob/master/LICENSE).

**Table of Contents**

  - [Android](#android)
  - [Artificial Intelligence](#artificial-intelligence)
  - [Assembler](#assembler)
  - [Cloud Computing](#cloud-computing)
  - [Command Line](#command-line)
  - [Compilers](#compilers)
  - [Computer science](#computer-science)
  - [Containers](#containers)
  - [DevOps](#devops)
  - [Education](#education)
  - [Java](#java)
  - [Javascript](#javascript)
  - [PostgreSQL](#postgresql)
  - [Python](#python)
  - [Unix](#unix)
  - [Vim](#vim)
  - [Miscellaneous](#miscellaneous)
  - [Temporary or unorganized](#temporary-or-unorganized)
  - [Further Reading](#further-reading)
  - [Credits](#credits)
  - [Disclaimer](#disclaimer)
  - [License](#license)

## Android
- [Android apps](https://www.youtube.com/playlist?list=PLGLfVvz_LVvSPjWpLPFEfOCbezi6vATIh)
- [Android tutorial](http://www.vogella.com/tutorials/Android/article.html)
- [Android training](https://developer.android.com/training/index.html)
- [Android development for beginners](https://www.udacity.com/course/android-development-for-beginners--ud837)
- [Developing Android apps](https://www.udacity.com/course/developing-android-apps--ud853)
- [Writing Android apps](http://lifehacker.com/i-want-to-write-android-apps-where-do-i-start-1643818268)
- [Sketch (design a mobile app)](https://www.youtube.com/watch?v=YjsQJShFewI)

## Artificial Intelligence
- [Berkeley AI Materials](http://ai.berkeley.edu/project_overview.html) ([HN discussion](https://news.ycombinator.com/item?id=10929985))
- [Video games and AI](http://togelius.blogspot.com/2016/01/why-video-games-are-essential-for.html)
- [Machine Learning](https://www.udacity.com/course/machine-learning-engineer-nanodegree--nd009)
- [Torch, a scientific computing framework for luajit](http://torch.ch/)
- [Neural networks](http://neuralnetworksanddeeplearning.com/chap6.html) ([HN discussion](https://news.ycombinator.com/item?id=9951352))
- [Artificial Neural Networks for beginners](http://blogs.mathworks.com/loren/2015/08/04/artificial-neural-networks-for-beginners/)
- [Machine learning](http://www.computervisiontalks.com/tag/machine-learning-class-10-701/) ([HN discussion](https://news.ycombinator.com/item?id=9920529))
- [Machine Learning](https://www.cs.ox.ac.uk/people/nando.defreitas/machinelearning/)
- [Google's free Deep Learning course](https://www.udacity.com/course/deep-learning--ud730)

## Assembler
- [CROBOTS (1985) (like CoreWar)](http://tpoindex.github.io/crobots/) ([HN discussion](https://news.ycombinator.com/item?id=10331849))

## Cloud Computing
- [Learn Mesos](http://open.mesosphere.com/intro-course/)
- [Learn cloud computing](https://cloudacademy.com)
- [Dynamo: Amazon's Highly Available Key-value Store](http://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf)

## Command Line
- [Learn code the hard way](http://cli.learncodethehardway.org/book/)
- [Bash / Sh](https://news.ycombinator.com/item?id=10068567)
- [Art of CLI](https://github.com/jlevy/the-art-of-command-line)
- [Command line course](https://www.codecademy.com/en/courses/learn-the-command-line)

## Compilers
- [Build a simple interpreter](http://ruslanspivak.com/lsbasi-part5/)
- [Compiler construction](https://news.ycombinator.com/item?id=10785164)
- [Compiler construction](https://www.inf.ethz.ch/personal/wirth/CompilerConstruction/index.html)
- [Papers on compilers](https://news.ycombinator.com/item?id=10786842)
- [Let's Build a Compiler, by Jack Crenshaw](http://compilers.iecc.com/crenshaw/)
- [Logic, Languages, Compilation, and Verification](http://www.cs.uoregon.edu/research/summerschool/summer12/curriculum.html)

## Computer Science
- [OSS University](https://github.com/open-source-society/computer-science-and-engineering)
- [Computer Science for all](http://www.cs.hmc.edu/csforall/)
- [Math for Computer Science](http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-042j-mathematics-for-computer-science-fall-2010/video-lectures/) ([HN discussion](https://news.ycombinator.com/item?id=9311752))
- [What is code - http](//www.bloomberg.com/graphics/2015-paul-ford-what-is-code/)
- [A plain english introduction to CAP Theorem](http://ksat.me/a-plain-english-introduction-to-cap-theorem/)
- [Critique to the CAP Theorem](http://markburgess.org/blog_cap.html)

## Containers
- [Docker for beginners](http://prakhar.me/docker-curriculum/)
- [Containers resources](https://github.com/borntorock/awesome-containers/blob/master/awesome-containers.md)
- [Network containers](https://www.zerotier.com/blog/?p=490)

## DevOps
- [Ops School](http://www.opsschool.org/en/latest/)

## Education
- [Lumiar (Ricardo Semler)](http://lumiar.org.br/index.php/a-escola/?lang=en)
- [International Baccalaureate](http://www.ibo.org/)
- [European Graduate School](http://www.egs.edu/department/philosophy-art-critical-thought/admissions-pact)
- [21st century education](https://minerva.kgi.edu/)

## Java
- [Learn Java the hard way](https://learnjavathehardway.org/book/ex00.html)
- [Course on Java](https://www.udemy.com/course/subscribe/?courseId=24823&dtcode=jPSadG83nzV3)
- [Tutorial on Java](https://www.udemy.com/java-tutorial/learn/#/lecture/131404)
- [Java basics](http://teamtreehouse.com/library/java-basics)
- [Intro to Java Programming](https://www.udacity.com/course/intro-to-java-programming--cs046)
- [Course on Eclipse](https://www.udemy.com/course/subscribe/?courseId=354422&dtcode=hxFBwbI3nzVe)

## Javascript
- [Grand Javascript school](http://raganwald.com/2015/04/24/hilberts-school.html) ([HN discussion](https://news.ycombinator.com/item?id=9439479))
- [Javascript game development](http://codeincomplete.com/games/)
- [Write Pacman in Javascript](http://www.masswerk.at/JavaPac/pacman-howto.html)
- [You don't know Javascript](https://github.com/getify/You-Dont-Know-JS)

## Postgresql
- [Postgres guide](http://www.postgresguide.com/) ([HN discussion](https://news.ycombinator.com/item?id=9993237))
- [Postgres CLI](http://pgcli.com/)
- [MySQL CLI (for comparison)](http://mycli.net/)
- [PostgreSQL command line](http://phili.pe/posts/postgresql-on-the-command-line/) ([HN discussion](https://news.ycombinator.com/item?id=10458866))
- [SQL tabs (PostgreSQL)](http://www.sqltabs.com/) ([HN discussion](https://news.ycombinator.com/item?id=10802631))
- [Embracing SQL in PostgreSQL](http://rob.conery.io/2015/02/24/embracing-sql-in-postgres/)
- [Curated list of great PostgreSQL resources](https://github.com/dhamaniasad/awesome-postgres)

## Python
- [Learn Python](http://aysinoruz.com/i-taught-myself-python-on-the-internet-and-so-can-you/)
- [ML + Python](https://news.ycombinator.com/item?id=9902524)
- [Intermediate python](http://book.pythontips.com/en/latest/) ([HN discussion](https://news.ycombinator.com/item?id=10075078))
- [Tutorials to learn Python](https://news.ycombinator.com/item?id=10135935)
- [Python Sudoku](http://norvig.com/sudoku.html)
- [Python IDE](http://pybee.org/)
- [Interactive Python](http://interactivepython.org/runestone/static/pythonds/index.html)
- [Python the hard way](http://learnpythonthehardway.org/book/) (3rd edition)
- [Norvig's python stuff](http://nbviewer.ipython.org/url/norvig.com/ipython/Probability.ipynb)
- [IDLE Python](http://www.tkdocs.com/tutorial/idle.html)
- [The Zen of Python](https://www.python.org/dev/peps/pep-0020/)

## Unix
- [Bro pages](http://bropages.org/browse)
- [Unix toolbox](http://cb.vu/unixtoolbox.xhtml)
- [Hardened BSD](https://hardenedbsd.org/)

## Vim
- [VIM as IDE](https://github.com/jez/vim-as-an-ide)
- [Learn VIM while playing a game](http://vim-adventures.com/) ([HN discussion](https://news.ycombinator.com/item?id=9250190))
- [Vim takeaways](http://sankho.github.io/web_log/2015/08/02/vim-8-takeaways-from-one-year-of-typing.html) ([HN discussion](https://news.ycombinator.com/item?id=9996088))
- [Study Vim](https://danielmiessler.com/study/vim/)
- [Vim galore](https://github.com/mhinz/vim-galore)

## Working in the US
- Calculating the federal income tax: https://www.khanacademy.org/economics-finance-domain/core-finance/taxes-topic/taxes/v/calculating-federal-taxes-and-take-home-pay
- 2016 federal tax rates: http://www.forbes.com/sites/kellyphillipserb/2015/10/21/irs-announces-2016-tax-rates-standard-deductions-exemption-amounts-and-more/
- California standard deductions: https://www.ftb.ca.gov/individuals/faq/net/902.shtml
- California tax brackets: http://www.tax-brackets.org/californiataxtable

## Miscellaneous
- [How to minimize procrastination](https://myelin.io/how-to-minimize-procrastination)
- [How to learn efficiently](http://lemire.me/blog/2014/12/30/how-to-learn-efficiently/) ([HN discussion](https://news.ycombinator.com/item?id=8815148))
- [Learn to read Korean](http://ryanestradadotcom.tumblr.com/post/20461267965/learn-to-read-korean-in-15-minutes) ([HN discussion](https://news.ycombinator.com/item?id=9935042))
- [Thinking about thinking](http://edge.org/events/the-edge-master-class-2007-a-short-course-in-thinking-about-thinking)
- [Philosophy](http://plato.stanford.edu/)
- [Math](http://www.math.ucla.edu/~tao/preprints/problem.ps) ([HN discussion](https://news.ycombinator.com/item?id=9942638))
- [React.js fundamentals](http://courses.reactjsprogram.com/courses/reactjsfundamentals)
- [Learning Paths by O'Reilly](http://shop.oreilly.com/category/learning-path.do)
- [DevOps Wiki](https://github.com/Leo-G/DevopsWiki/blob/master/README.md)
- [Computer Science video lectures](http://csvideolectures.com/)

## Temporary or unorganized
- [Entrepreneur](https://www.udacity.com/course/tech-entrepreneur-nanodegree--nd007)
- [Spinnaker, deploy artifacts to the cloud](http://spinnaker.io/)
- [Flux / React](https://medium.com/code-cartoons/a-cartoon-guide-to-flux-6157355ab207)
- [Mapzen search](https://news.ycombinator.com/item?id=10318541)
- [Book "Architecture of open source applications"](http://aosabook.org/en/index.html)
- [Kali Linux](https://www.kali.org/downloads/)
- [APIs](https://news.ycombinator.com/item?id=9987838)
- [Swift](http://books.aidanf.net/learn-swift/introduction)
- [Security](http://99percentinvisible.org/episode/perfect-security/) ([HN discussion](https://news.ycombinator.com/item?id=9545972))
- [Rust](http://blog.rust-lang.org/2015/04/24/Rust-Once-Run-Everywhere.html)
- [Erlang / Elixir](https://news.ycombinator.com/item?id=9426103)
- [Competence Matrix](http://sijinjoseph.com/programmer-competency-matrix/)
- [Data Science masters](http://datasciencemasters.org/)
- [Bitcoin](https://bitcoin.org/bitcoin.pdf)
- [RegEx crossword](https://regexcrossword.com/)
- [Scala](https://scala.epfl.ch/)

## Further reading
n.a.

# Content ends here

## Credits

Many thanks to [all contributors](https://github.com/simonebrunozzi/open-guide-to-learning-tech-geek-nerdy-stuff/graphs/contributors) to this project.
Thanks also to those who have given detailed feedback - they will be listed below here.
Example:
[anonymous coward](https://twitter.com/anonymous-coward),

The original author is Simone Brunozzi [Twitter](https://twitter.com/simon) [blog](http://www.brunozzi.com) [medium](https://medium.com/simone-brunozzi)

## Disclaimer
*This guide and all associated comments and discussion do not constitute any advice in any respect, and they do not represent an endorsement of any product or service.
No reader should act or refrain from acting on the basis of any information presented herein without seeking the advice of counsel in the relevant jurisdiction.
The author(s) expressly disclaim all liability in respect of any actions taken or not taken based on any contents of this guide or associated content.*

## License
[![Creative Commons License](http://i.creativecommons.org/p/zero/1.0/88x31.png)](https://creativecommons.org/publicdomain/zero/1.0/)

This work is licensed under a Creative Commons CC0 1.0 Universal (CC0 1.0) license.
License details [are available here](https://github.com/simonebrunozzi/open-guide-to-learning-tech-geek-nerdy-stuff/blob/master/LICENSE).


text:
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Express 2013 for Windows Desktop
VisualStudioVersion = 12.0.21005.1
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "tetris-win32", "tetris-win32.vcxproj", "{278AC16E-53B1-4910-BAD7-5B146DAF9B4E}"
EndProject
Global
	GlobalSection(SolutionConfigurationPlatforms) = preSolution
		Debug|Win32 = Debug|Win32
		Release|Win32 = Release|Win32
	EndGlobalSection
	GlobalSection(ProjectConfigurationPlatforms) = postSolution
		{278AC16E-53B1-4910-BAD7-5B146DAF9B4E}.Debug|Win32.ActiveCfg = Debug|Win32
		{278AC16E-53B1-4910-BAD7-5B146DAF9B4E}.Debug|Win32.Build.0 = Debug|Win32
		{278AC16E-53B1-4910-BAD7-5B146DAF9B4E}.Release|Win32.ActiveCfg = Release|Win32
		{278AC16E-53B1-4910-BAD7-5B146DAF9B4E}.Release|Win32.Build.0 = Release|Win32
	EndGlobalSection
	GlobalSection(SolutionProperties) = preSolution
		HideSolutionNode = FALSE
	EndGlobalSection
EndGlobal

mime_type: text/x-c++


text:
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <PropertyGroup Label="Globals">
    <ProjectGuid>{278AC16E-53B1-4910-BAD7-5B146DAF9B4E}</ProjectGuid>
    <Keyword>Win32Proj</Keyword>
    <RootNamespace>tetriswin32</RootNamespace>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>true</UseDebugLibraries>
    <PlatformToolset>v120</PlatformToolset>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
    <UseDebugLibraries>false</UseDebugLibraries>
    <PlatformToolset>v120</PlatformToolset>
    <WholeProgramOptimization>true</WholeProgramOptimization>
    <CharacterSet>Unicode</CharacterSet>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <LinkIncremental>true</LinkIncremental>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <LinkIncremental>false</LinkIncremental>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <WarningLevel>Level3</WarningLevel>
      <Optimization>Disabled</Optimization>
      <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <AdditionalDependencies>Winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <WarningLevel>Level3</WarningLevel>
      <PrecompiledHeader>
      </PrecompiledHeader>
      <Optimization>MaxSpeed</Optimization>
      <FunctionLevelLinking>true</FunctionLevelLinking>
      <IntrinsicFunctions>true</IntrinsicFunctions>
      <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
    </ClCompile>
    <Link>
      <SubSystem>Windows</SubSystem>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <EnableCOMDATFolding>true</EnableCOMDATFolding>
      <OptimizeReferences>true</OptimizeReferences>
      <AdditionalDependencies>Winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
    <ClCompile Include="src\DrawEngine.cpp" />
    <ClCompile Include="src\Game.cpp" />
    <ClCompile Include="src\Level.cpp" />
    <ClCompile Include="src\main.cpp" />
    <ClCompile Include="src\Piece.cpp" />
    <ClCompile Include="src\PieceSet.cpp" />
  </ItemGroup>
  <ItemGroup>
    <ClInclude Include="src\DrawEngine.h" />
    <ClInclude Include="src\Game.h" />
    <ClInclude Include="src\Level.h" />
    <ClInclude Include="src\Piece.h" />
    <ClInclude Include="src\PieceSet.h" />
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
</Project>


text:
Classic tetris game implemented with Win32 API.

![Screenshot](https://raw.github.com/eliangcs/tetris-win32/master/screenshot.png)


text:
#ifndef GAME_H
#define GAME_H

#include "Level.h"
#include "PieceSet.h"
#include "Piece.h"

//
// Game flow.
// Only Game and DrawEngine are exposed to main().
//
class Game
{
public:
    Game(DrawEngine &de);
    ~Game();

    // Restarts the game
    void restart();

    // Handles player's key press
    bool keyPress(int vk);

    // Updates data or graphics
    void timerUpdate();

    // Pass true to pause, pass false to resume
    void pause(bool paused);

    // Called on WM_PAINT
    void repaint() const;

    bool isGameOver() const;

protected:
    // Shows GAME OVER message
    inline void drawGameOver() const
    {
        de.drawText(TEXT("GAME OVER"), 3, 10);
        de.drawText(TEXT("Press ENTER to restart"), 2, 9);
    }

    // Shows PAUSE message
    inline void drawPause() const
    {
        de.drawText(TEXT("PAUSE"), 4, 10);
        de.drawText(TEXT("Press PAUSE again to continue"), 1, 9);
    }

    Level *level;
    DrawEngine &de;

    // Is game currently paused?
    bool isPaused;
};

#endif // GAME_H


text:
#include "PieceSet.h"

PieceSet::PieceSet()
{
    for (int i = 0; i < NUM_PIECES; i++)
        for (int j = 0; j < NUM_ROTATIONS; j++)
            pieces[i][j] = 0;

    POINT apt[NUM_ROTATIONS];

    // 0, I piece, red
    apt[0].x = 0;    apt[0].y = 0;
    apt[1].x = 0;    apt[1].y = 1;
    apt[2].x = 0;    apt[2].y = 2;
    apt[3].x = 0;    apt[3].y = 3;
    pieces[0][0] = new Piece(0, 0, RGB(255,0,0), apt);

    // 1, L piece, orange
    apt[0].x = 0;    apt[0].y = 0;
    apt[1].x = 1;    apt[1].y = 0;
    apt[2].x = 0;    apt[2].y = 1;
    apt[3].x = 0;    apt[3].y = 2;
    pieces[1][0] = new Piece(1, 0, RGB(230,130,24), apt);

    // 2, counter-L piece, yellow
    apt[0].x = 0;    apt[0].y = 0;
    apt[1].x = 1;    apt[1].y = 0;
    apt[2].x = 1;    apt[2].y = 1;
    apt[3].x = 1;    apt[3].y = 2;
    pieces[2][0] = new Piece(2, 0, RGB(255,255,0), apt);

    // 3, S piece, green
    apt[0].x = 0;    apt[0].y = 0;
    apt[1].x = 1;    apt[1].y = 0;
    apt[2].x = 1;    apt[2].y = 1;
    apt[3].x = 2;    apt[3].y = 1;
    pieces[3][0] = new Piece(3, 0, RGB(120,200,80), apt);

    // 4, Z piece, blue
    apt[0].x = 1;    apt[0].y = 0;
    apt[1].x = 2;    apt[1].y = 0;
    apt[2].x = 0;    apt[2].y = 1;
    apt[3].x = 1;    apt[3].y = 1;
    pieces[4][0] = new Piece(4, 0, RGB(100,180,255), apt);

    // 5, Square piece, dark blue
    apt[0].x = 0;    apt[0].y = 0;
    apt[1].x = 1;    apt[1].y = 0;
    apt[2].x = 0;    apt[2].y = 1;
    apt[3].x = 1;    apt[3].y = 1;
    pieces[5][0] = new Piece(5, 0, RGB(20,100,200), apt);

    // 6, T piece, purple
    apt[0].x = 0;    apt[0].y = 0;
    apt[1].x = 1;    apt[1].y = 0;
    apt[2].x = 2;    apt[2].y = 0;
    apt[3].x = 1;    apt[3].y = 1;
    pieces[6][0] = new Piece(6, 0, RGB(220,180,255), apt);

    // Create piece rotations
    rotateAll();
}

PieceSet::~PieceSet()
{
    for (int i = 0; i < NUM_PIECES; i++)
        for (int j = 0; j < NUM_ROTATIONS; j++)
            if (pieces[i][j] != 0)
                delete pieces[i][j];
}

Piece *PieceSet::getPiece(int id, int rotation) const
{
    if (id >= NUM_PIECES || id < 0 || rotation >= NUM_ROTATIONS || rotation < 0)
        return NULL;
    return pieces[id][rotation];
}

void PieceSet::rotateAll()
{
    POINT apt[NUM_ROTATIONS];
    for (int i = 0; i < NUM_PIECES; i++)
    {
        pieces[i][0]->getBody(apt);
        for (int j = 1; j < NUM_ROTATIONS; j++)
        {
            rotate(apt);
            if (pieces[i][j] != 0)
                delete pieces[i][j];
            pieces[i][j] = new Piece(i, j, pieces[i][0]->getColor(), apt);
        }
    }
}

void PieceSet::rotate(POINT* apt, int numPoints)
{
    int tmp;

    // X' = -Y
    // Y' = X
    for (int i = 0; i < numPoints; i++)
    {
        tmp = apt[i].x;
        apt[i].x = -apt[i].y;
        apt[i].y = tmp;
    }
}


text:
#include "Piece.h"
#include <iostream>

using namespace std;

Piece::Piece(int pieceId, int pieceRotation, COLORREF pieceColor,
             const POINT *apt, int numPoints) :
id(pieceId), rotation(pieceRotation), nPoints(numPoints),
color(pieceColor), width(0), height(0)
{
    POINT bottomLeft = apt[0];

    for (int i = 1; i < nPoints; i++)
    {
        bottomLeft.x = min(apt[i].x, bottomLeft.x);
        bottomLeft.y = min(apt[i].y, bottomLeft.y);
    }

    body = new POINT[nPoints];

    for (int i = 0; i < nPoints; i++)
    {
        body[i].x = apt[i].x - bottomLeft.x;
        body[i].y = apt[i].y - bottomLeft.y;

        width = max((int)body[i].x + 1, width);
        height = max((int)body[i].y + 1, height);
    }
}

Piece::~Piece()
{
    if (body)
        delete [] body;
}

void Piece::getBody(POINT *apt) const
{
    for (int i = 0; i < nPoints; i++)
        apt[i] = body[i];
}

int Piece::getSkirt(POINT *apt) const
{
    int i = 0;
    for (int x = 0; x < width; x++)
    {
        for (int y = 0; y < height; y++)
        {
            if (isPointExists(x, y))
            {
                apt[i].x = x;
                apt[i].y = y;
                i++;
                break;
            }
        }
    }
    return i;
}

int Piece::getLeftSide(POINT *apt) const
{
    int i = 0;
    for (int y = 0; y < height; y++)
    {
        for (int x = 0; x < height; x++)
        {
            if (isPointExists(x, y))
            {
                apt[i].x = x;
                apt[i].y = y;
                i++;
                break;
            }
        }
    }
    return i;
}

int Piece::getRightSide(POINT *apt) const
{
    int i = 0;
    for (int y = 0; y < height; y++)
    {
        for (int x = width - 1; x >= 0; x--)
        {
            if (isPointExists(x, y))
            {
                apt[i].x = x;
                apt[i].y = y;
                i++;
                break;
            }
        }
    }
    return i;
}

void Piece::print() const
{
    cout << "width = " << width << endl;
    cout << "height = " << height << endl;
    cout << "nPoints = " << nPoints << endl;
    cout << "color = " << hex << color << endl;
    for (int y = height - 1; y >= 0; y--)
    {
        for (int x = 0; x < width; x++)
        {
            if (isPointExists(x, y))
				cout << "#";
            else
                cout << " ";
        }
        cout << endl;
    }
}

bool Piece::isPointExists(int x, int y) const
{
    for (int i = 0; i < 4; i++)
    {
        if (body[i].x == x && body[i].y == y)
            return true;
    }
    return false;
}


text:
#ifndef DRAW_ENGINE_H
#define DRAW_ENGINE_H

#include "Piece.h"
#include <windows.h>

//
// Draw engine implemented with Win32 API GDI.
//
class DrawEngine
{
public:
    // hdc: handle to DC
    // hwnd: handle to window
    // pxPerBlock: cell size in pixels
    // width & height: level width and height
    DrawEngine(HDC hdc, HWND hwnd, int pxPerBlock = 25,
               int width = 10, int height = 20);
    ~DrawEngine();

    // Fills a cell
    void drawBlock(int x, int y, COLORREF color);

    // Draws UI (gray area)
    void drawInterface();

    // Draws a text message
    void drawText(TCHAR *szText, int x, int y) const;

    // Draws all kinds of info
    void drawScore(int score, int x, int y) const;
    void drawSpeed(int speed, int x, int y) const;
    void drawNextPiece(Piece &piece, int x, int y);

protected:
    HDC hdc;     // Handle to DC
    HWND hwnd;   // Handle to window
    RECT rect;   // For internal temporary usage
    int width;   // Level width in cells
    int height;  // Level height
};

#endif // DRAW_ENGINE_H


text:
#include "Level.h"
#include <ctime>

Level::Level(DrawEngine &de, int width, int height) :
de(de), width(width), height(height), lastTime(0.0), speed(500), score(-1)
{
    srand(time(0));

    // Allocate the drawing board
    board = new COLORREF*[width];
    for (int i = 0; i < width; i++)
    {
        board[i] = new COLORREF[height];
        for (int j = 0; j < height; j++)
            board[i][j] = RGB(0, 0, 0);
    }

    // 初始化目前和下一個方塊
    current = 0;
    next = pieceSet.getRandomPiece();
}

Level::~Level()
{
    for (int i = 0; i < width; i++)
        delete [] board[i];
    delete [] board;
}

void Level::drawBoard() const
{
    for (int i = 0; i < width; i++)
        for (int j = 0; j < height; j++)
            de.drawBlock(i, j, board[i][j]);
}

void Level::timerUpdate()
{
    // If the time isn't up, don't drop nor update
    currentTime = timeGetTime();
    if (currentTime - lastTime < speed)
        return;

    // Time's up, drop
    // If the piece hits the bottom, check if player gets score, drop the next
    // piece, increase speed, redraw info
    // If player gets score, increase more speed
    if (current == NULL || !move(0, -1))
    {
        int lines = clearRows();
        speed = max(speed - 2 * lines, 100);
        score += 1 + lines * lines * 5;
        dropRandomPiece();
        drawScore();
        drawSpeed();
        drawNextPiece();
    }

    lastTime = timeGetTime();
}

bool Level::place(int x, int y, const Piece &piece)
{
    // Out of boundary or the position has been filled
    if (x + piece.getWidth() > width || isCovered(piece, x, y))
        return false;

    posX = x;
    posY = y;

    POINT apt[4];
    piece.getBody(apt);

    COLORREF color = piece.getColor();

    for (int i = 0; i < 4; i++)
    {
        if (y + apt[i].y > height - 1)
            continue;
        board[x+apt[i].x][y+apt[i].y] = color;
    }
    return true;
}

bool Level::rotate()
{
    Piece *tmp = current;

    // Move the piece if it needs some space to rotate
    int disX = max(posX + current->getHeight() - width, 0);

    // Go to next rotation state (0-3)
    int rotation = (current->getRotation() + 1) % PieceSet::NUM_ROTATIONS;

    clear(*current);
    current = pieceSet.getPiece(current->getId(), rotation);

    // Rotate successfully
    if (place(posX - disX, posY, *current))
        return true;

    // If the piece cannot rotate due to insufficient space, undo it
    current = tmp;
    place(posX, posY, *current);
    return false;
}

bool Level::move(int cxDistance, int cyDistance)
{
    if (posX + cxDistance < 0 || posY + cyDistance < 0 ||
        posX + current->getWidth() + cxDistance > width)
        return false;
    if (cxDistance < 0 && isHitLeft())
        return false;
    if (cxDistance > 0 && isHitRight())
        return false;
    if (cyDistance < 0 && isHitBottom())
        return false;
    clear(*current);
    return place(posX + cxDistance, posY + cyDistance, *current);
}

void Level::clear(const Piece &piece)
{
    POINT apt[4];
    piece.getBody(apt);
    int x, y;
    for (int i = 0; i < 4; i++) {
        x = posX + apt[i].x;
        y = posY + apt[i].y;
        if (x > width -1 || y > height - 1)
            continue;
        board[posX+apt[i].x][posY+apt[i].y] = RGB(0,0,0);
    }
}

void Level::dropRandomPiece()
{
    current = next;
    next = pieceSet.getRandomPiece();
    place(3, height - 1, *current);
}

bool Level::isHitBottom() const
{
    POINT apt[4];
    int n = current->getSkirt(apt);
    int x, y;
    for (int i = 0; i < n; i++)
    {
        x = posX + apt[i].x;
        y = posY + apt[i].y;
        if (y < height && (y == 0 || board[x][y-1] != RGB(0,0,0)))
            return true;
    }
    return false;
}

bool Level::isHitLeft() const
{
    POINT apt[4];
    int n = current->getLeftSide(apt);
    int x, y;
    for (int i = 0; i < n; i++)
    {
        x = posX + apt[i].x;
        y = posY + apt[i].y;
        if (y > height - 1)
            continue;
        if (x == 0 || board[x-1][y] != RGB(0,0,0))
            return true;
    }
    return false;
}

bool Level::isHitRight() const
{
    POINT apt[4];
    int n = current->getRightSide(apt);
    int x, y;
    for (int i = 0; i < n; i++)
    {
        x = posX + apt[i].x;
        y = posY + apt[i].y;
        if (y > height - 1)
            continue;
        if (x == width - 1 || board[x+1][y] != RGB(0,0,0))
            return true;
    }
    return false;
}

bool Level::isCovered(const Piece &piece, int x, int y) const
{
    POINT apt[4];
    piece.getBody(apt);
    int tmpX, tmpY;
    for (int i = 0; i < 4; i++)
    {
        tmpX = apt[i].x + x;
        tmpY = apt[i].y + y;
        if (tmpX > width - 1 || tmpY > height -1)
            continue;
        if (board[tmpX][tmpY] != RGB(0,0,0))
            return true;
    }
    return false;
}

int Level::clearRows()
{
    bool isComplete;
    int rows = 0;

    for (int i = 0; i < height; i++)
    {
        for (int j = 0; j < width; j++)
        {
            if (board[j][i] == RGB(0,0,0))
            {
                isComplete = false;
                break;
            }
            // The row is full
            if (j == width - 1)
                isComplete = true;
        }
        // If the row is full, clear it (fill with black)
        if (isComplete)
        {
            for (int j = 0; j < width; j++)
                board[j][i] = RGB(0,0,0);

            // Move rows down
            for (int k = i; k < height - 1; k++)
            {
                for (int m = 0; m < width; m++)
                    board[m][k] = board[m][k+1];
            }
            i = -1;
            rows++;
        }
    }
    return rows;
}

bool Level::isGameOver()
{
    // Exclude the current piece
    if (current)
        clear(*current);

    // If there's a piece on the top, game over
    for (int i = 0; i < width; i++) {
        if (board[i][height-1]) {
            if (current)
                place(posX, posY, *current);
            return true;
        }
    }

    // Put the current piece back
    if (current != 0)
        place(posX, posY, *current);
    return false;
}

void Level::drawSpeed() const
{
    de.drawSpeed((500 - speed) / 2, width + 1, 12);
}

void Level::drawScore() const
{
    de.drawScore(score, width + 1, 13);
}

void Level::drawNextPiece() const
{
    de.drawNextPiece(*next, width + 1, 14);
}


text:
#include "Game.h"
#include <iostream>

using namespace std;

Game::Game(DrawEngine &de) :
de(de), isPaused(false)
{
    level = new Level(de, 10, 20);
}

Game::~Game()
{
    delete level;
}

void Game::restart()
{
    delete level;
    level = new Level(de, 10, 20);
    isPaused = false;
    repaint();
}

bool Game::keyPress(int vk)
{
    // When pausing, ignore keys other than PAUSE and ENTER
    if (vk != VK_PAUSE && vk != VK_RETURN && isPaused)
        return false;

    switch (vk)
    {
        case VK_UP:
            level->rotate();
            break;
        case VK_DOWN:
            level->move(0, -1);
            break;
        case VK_LEFT:
            level->move(-1, 0);
            break;
        case VK_RIGHT:
            level->move(1, 0);
            break;
        case VK_SPACE:
            level->rotate();
            break;
        case VK_PAUSE:
            pause(!isPaused);
            break;
        case VK_RETURN:
            // You can only restart on game over
            if (level->isGameOver())
                restart();
        default:
            return false;
    }
    return true;
}

void Game::timerUpdate()
{
    // Don't update game when pausing
    if (isPaused)
        return;

    // If game is over, show GAME OVER
    if (level->isGameOver()) {
        isPaused = true;
        drawGameOver();
        return;
    }

    // Update game data
    level->timerUpdate();

    // Redraw
    level->drawBoard();
}

void Game::pause(bool paused)
{
    // Don't pause if game is over
    if (isGameOver())
        return;

    isPaused = paused;
    if (paused)
        drawPause();
    level->drawScore();
    level->drawSpeed();
}

void Game::repaint() const
{
    de.drawInterface();
    level->drawScore();
    level->drawSpeed();
    level->drawNextPiece();
    level->drawBoard();
    if (level->isGameOver())
        drawGameOver();
    else if (isPaused)
        drawPause();
}

bool Game::isGameOver() const
{
    return level->isGameOver();
}


text:
#include "Piece.h"
#include "Game.h"
#include <windows.h>
#include <iostream>

using namespace std;

const int PX_PER_BLOCK = 25;    // Cell size in pixels
const int SCREEN_WIDTH = 10;    // Level width in cells
const int SCREEN_HEIGHT = 20;   // Level height in cells
const int GAME_SPEED = 33;      // Update the game every GAME_SPEED millisecs (= 1/fps)
const int TIMER_ID = 1;

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   PSTR szCmdLine, int iCmdShow)
{

    static TCHAR szAppName[] = TEXT("tetris");
    HWND hwnd;
    MSG msg;
    WNDCLASSEX wc;

    // We need to repaint a lot, using CS_OWNDC is more efficient
    wc.cbSize = sizeof(WNDCLASSEX);
    wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
    wc.lpfnWndProc = WndProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName = NULL;
    wc.lpszClassName = szAppName;
    wc.hIconSm = NULL;

    if (!RegisterClassEx(&wc))
    {
        MessageBox(NULL, TEXT("Program requires Windows NT!"),
                   szAppName, MB_ICONERROR);
        return 0;
    }

    hwnd = CreateWindow(szAppName,
                        TEXT("Eliang's Tetris"),
                        WS_MINIMIZEBOX | WS_SYSMENU,  // No window resizing
                        CW_USEDEFAULT,
                        CW_USEDEFAULT,
                        SCREEN_WIDTH * PX_PER_BLOCK + 156,
                        SCREEN_HEIGHT * PX_PER_BLOCK + 25,
                        NULL,
                        NULL,
                        hInstance,
                        NULL);

    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);

    while (GetMessage(&msg, NULL, 0, 0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    static Game *game;
    static DrawEngine *de;

    switch (message)
    {
        case WM_CREATE:
            hdc = GetDC(hwnd);

            de = new DrawEngine(hdc, hwnd, PX_PER_BLOCK);
            game = new Game(*de);
            SetTimer(hwnd, TIMER_ID, GAME_SPEED, NULL);

            ReleaseDC(hwnd, hdc);
            return 0;

        case WM_KEYDOWN:
            game->keyPress(wParam);
            return 0;

        case WM_TIMER:
            game->timerUpdate();
            return 0;

        case WM_KILLFOCUS:
            KillTimer(hwnd, TIMER_ID);
            game->pause(true);
            return 0;

        case WM_SETFOCUS:
            SetTimer(hwnd, TIMER_ID, GAME_SPEED, NULL);
            return 0;

        case WM_PAINT:
            hdc = BeginPaint(hwnd, &ps);
            game->repaint();
            EndPaint(hwnd, &ps);
            return 0;

        case WM_DESTROY:
            delete de;
            delete game;
            KillTimer(hwnd, TIMER_ID);
            PostQuitMessage(0);
            return 0;

    }

    return DefWindowProc(hwnd, message, wParam, lParam);
}


text:
#ifndef LEVEL_H
#define LEVEL_H

#include "DrawEngine.h"
#include "PieceSet.h"
#include <windows.h>

//
// Level stores current snapshot of the game, including the dropping piece,
// the next piece, the piece generator (PieceSet), the position of the
// dropping piece, the width and height of the level, the dropping speed,
// and a two-dimentional color array that is used to represent the canvas.
//
class Level
{
public:
    // de: used to draw the level
    // width & height: level size in cells
    Level(DrawEngine &de, int width = 10, int height = 20);
    ~Level();

    // Draws the level
    void drawBoard() const;

    // Rotates the dropping piece, returns true if successful
    bool rotate();

    // Moves the dropping piece, returns true if successful
    // cxDistance is horizontal movement, positive value is right
    // cyDistance is vertical movement, positive value is up (normally it's
    // negaive)
    bool move(int cxDistance, int cyDistance);

    // Updates the level based on the current speed
    void timerUpdate();

    bool isGameOver();

    // Draw different kinds of info
    void drawSpeed() const;
    void drawScore() const;
    void drawNextPiece() const;

protected:
    // Places a piece somewhere
    // If there isn't enough space, does nothing and returns false
    bool place(int x, int y, const Piece &piece);

    // Clears a piece on the canvas
    void clear(const Piece& piece);

    // Releases the next dropping piece
    void dropRandomPiece();

    // Checks if the piece hits the boundary
    bool isHitBottom() const;
    bool isHitLeft() const;
    bool isHitRight() const;

    // Checks if a piece can move to a position
    bool isCovered(const Piece &piece, int x, int y) const;

    // Clears "full" rows, returns the number of rows being cleared
    int clearRows();

    COLORREF **board;    // The cavnas, the drawing board
    DrawEngine &de;      // Does graphics stuffs
    PieceSet pieceSet;   // Piece generator
    Piece *current;      // Current dropping piece
    Piece *next;         // Next piece
    int width;           // Level width (in cells)
    int height;          // Level height
    int posX;            // X coordinate of dropping piece (Cartesian system)
    int posY;            // Y coordinate of dropping piece
    int speed;           // Drop a cell every _speed_ millisecs
    double lastTime;     // Last time updated
    double currentTime;  // Current update time
    int score;           // Player's score
};

#endif // LEVEL_H


text:
#include "DrawEngine.h"

DrawEngine::DrawEngine(HDC hdc, HWND hwnd, int pxPerBlock,
                       int width, int height) :
hdc(hdc), hwnd(hwnd), width(width), height(height)
{
    GetClientRect(hwnd, &rect);

    SaveDC(hdc);

    // Set up coordinate system
    SetMapMode(hdc, MM_ISOTROPIC);
    SetViewportExtEx(hdc, pxPerBlock, pxPerBlock, 0);
    SetWindowExtEx(hdc, 1, -1, 0);
    SetViewportOrgEx(hdc, 0, rect.bottom, 0);

    // Set default colors
    SetTextColor(hdc, RGB(255,255,255));
    SetBkColor(hdc, RGB(70,70,70));
    SetBkMode(hdc, TRANSPARENT);
}

DrawEngine::~DrawEngine()
{
    // Restore coordinate system
    RestoreDC(hdc, -1);
}

void DrawEngine::drawBlock(int x, int y, COLORREF color)
{
    HBRUSH hBrush = CreateSolidBrush(color);
    rect.left = x;
    rect.right = x + 1;
    rect.top = y;
    rect.bottom = y + 1;

    FillRect(hdc, &rect, hBrush);

    // Draw left and bottom black border
    MoveToEx(hdc, x, y + 1, NULL);
    LineTo(hdc, x, y);
    LineTo(hdc, x + 1, y);
    DeleteObject(hBrush);
}

void DrawEngine::drawInterface()
{
    // Draw a gray area at the right
    HBRUSH hBrush = CreateSolidBrush(RGB(70,70,70));
    rect.top = height;
    rect.left = width;
    rect.bottom = 0;
    rect.right = width + 8;
    FillRect(hdc, &rect, hBrush);
    DeleteObject(hBrush);
}

void DrawEngine::drawText(TCHAR *szText, int x, int y) const
{
    TextOut(hdc, x, y, szText, lstrlen(szText));
}

void DrawEngine::drawScore(int score, int x, int y) const
{
    TCHAR szBuffer[20];
    int len = wsprintf(szBuffer, TEXT("Score: %6d"), score);
    SetBkMode(hdc, OPAQUE);
    TextOut(hdc, x, y, szBuffer, len);
    SetBkMode(hdc, TRANSPARENT);
}

void DrawEngine::drawSpeed(int speed, int x, int y) const
{
    TCHAR szBuffer[20];
    int len = wsprintf(szBuffer, TEXT("Speed: %6d"), speed);
    SetBkMode(hdc, OPAQUE);
    TextOut(hdc, x, y, szBuffer, len);
    SetBkMode(hdc, TRANSPARENT);
}

void DrawEngine::drawNextPiece(Piece &piece, int x, int y)
{
    TCHAR szBuffer[] = TEXT("Next:");
    TextOut(hdc, x, y + 5, szBuffer, lstrlen(szBuffer));
    COLORREF color = piece.getColor();

    // Draw the piece in a 4x4 square area
    for (int i = 0; i < 4; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            if (piece.isPointExists(i, j))
                drawBlock(i + x, j + y, color);
            else
                drawBlock(i + x, j + y, RGB(0,0,0));
        }
    }
}


text:
#ifndef PIECE_H
#define PIECE_H

#include <windows.h>

//
// A piece in Teris game. This class is only used by PieceSet. Other classes
// access Piece through PieceSet.
//
// Every piece is composed by 4 POINTs, using Cartesian coordinate system.
// That is, the most bottom left point is (0, 0), the values on x-axis
// increase to the right, and values on y-axis increase to the top.
//
// To represent a piece, it is snapped to the bottom-left corner. For example,
// when the 'I' piece stands vertically, the point array stores:
// (0,0) (0,1) (0,2) (0,3)
//
class Piece
{
public:
    // pieceId: piece type ID
    // pieceRotation: how many time is the piece rotated (0-3)
    // pieceColor: piece color in RGB
    // apt: array of points of which the piece is composed. This constructor
    //      moves these points automatically to snap the piece to bottom-left
    //      corner (0,0)
    // numPoints: number of points in apt
    Piece(int pieceId, int pieceRotation, COLORREF pieceColor,
          const POINT *apt, int numPoints = 4);
    ~Piece();

    // Getters for piece properties
    inline int getWidth() const { return width; }
    inline int getHeight() const { return height; }
    inline int getNPoints() const { return nPoints; }
    inline int getId() const { return id; }
    inline int getRotation() const { return rotation; }
    inline COLORREF getColor() const { return color; }

    // If any of the following methods accepts a POINT pointer, make sure the
    // size of the array is big enough

    // Gets the points of the piece
    void getBody(POINT *apt) const;

    // Gets the bottom, left, or right part of points of the piece
    int getSkirt(POINT *apt) const;
    int getLeftSide(POINT *apt) const;
    int getRightSide(POINT *apt) const;

    // Determines if the piece has a point (x, y)
    bool isPointExists(int x, int y) const;

    // Prints a piece (for debugging)
    void print() const;

protected:
    // POINT array of which the piece is composed
    POINT *body;

    // Number of points in body
    int nPoints;

    // Make rotation more faster
    int width;
    int height;

    // Piece type ID and rotation
    int id;
    int rotation;

    // Piece color in RGB
    COLORREF color;
};

#endif // PIECE_H


text:
#ifndef PIECESET_H
#define PIECESET_H

#include "Piece.h"

//
// PieceSet generates 7 types of pieces. Each piece has 4 rotations, so there
// are 7 x 4 = 28 configurations in total.
//
// All 28 configurations are kept in memory after you new PieceSet(). To get
// get piece, use getPiece() or getRandomPiece().
//
class PieceSet
{
public:
    // Constants
    enum { NUM_ROTATIONS = 4, NUM_PIECES = 7 };

    PieceSet();
    ~PieceSet();

    // Gets a specific piece
    // id: one of 7 piece types (0-6)
    // rotation: one of 4 rotations (0-3)
    Piece *getPiece(int id, int rotation = 0) const;

    // Gets a random piece
    inline Piece *getRandomPiece() const
    {
        return getPiece(rand() % NUM_PIECES, rand() % NUM_ROTATIONS);
    }

protected:
    // Stores all 28 configurations of pieces
    Piece *pieces[NUM_PIECES][NUM_ROTATIONS];

    // Initializes piece rotations
    void rotateAll();

    // Rotates points by 90 degrees counterclockwise
    void rotate(POINT *apt, int numPoints = 4);
};

#endif // PIECESET_H


text:
---
title: "Fundamentals of RMarkdown"
author: "Mike Frank & Chris Hartgerink"
date: "July 31st, 2017"
output:
    revealjs::revealjs_presentation:
        theme: black
        highlight: pygments
        incremental: true
        center: true
        transition: slide
        reveal_options:
            slideNumber: true
        fig_caption: false
bibliography: library.bib
---

## Workshop

1. Short intro to Markdown (this!)
2. A document you can work through to get started
3. Exercises along the way where we'll highlight how to make useful documents (e.g. APA manuscript)
4. No need to stay until end if you feel you've got what you wanted

## Learning goals

By the end of this workshop you should:

* Know what Markdown is and how the syntax works,
* See how to integrate code and data with RMarkdown,
* Understand the different output formats from RMarkdown and how to generate them
* Know about generating APA format files with [`papaja`](https://github.com/crsh/papaja) and bibtex.

## RMarkdown = R + Markdown

1. It combines the magic of R with the simplicity of Markdown documents
1. The purpose: write your manuscripts and automatically insert results!
1. Use cases (amongst others):
  * prevent rounding errors
  * promote computational reproducibility
  * encourage error correction by minimizing manual work

## The Markdown

- Markdown is the simplest document language!
- Open standard, convertable into `.tex`, `.docx`, `.html`, `.pdf`, etc
- You can [learn Markdown in five (!) minutes](https://learnxinyminutes.com/docs/markdown/)
- Despite being simple, very powerful and used on many web platforms

## Basic Markdown: headings

- `# Header 1` creates a heading of the first level
- `## Header 2` creates a heading of the _second_ level
- `### Header 3` ...
- etc

## Basic Markdown: letter styles

- `**bold**` creates **bold**
- `*italic*` creates *italic*
- `***bold and italic!***` creates ***bold and italic!***

## The R

- If you're here, you probably know R
- Programming language for statistics
- Packages to add functionality
- Everything open-source!

## Combining R and Rmarkdown

- Can write text, include code
- We can include both code and its outputs, or just one of the two
- "Literate programming": mix code and explanation so that it's easier to figure out what's going on.

## Example code chunk

```{r}
x <- rnorm(100, 50, 20)
y <- rnorm(143, 51, 20)

t.test(x, y)
```

## Example in line

1. However, we can also evaluate code in text, and replace text with output
1. For example, let's round $\pi$ to four decimal places, using the code `round(pi, 4)`
  * `r round(pi, 4)`

<!-- ## RMarkdown is more powerful -->

<!-- - It's not just about individual results.  -->
<!-- - Ensures data preparation, analysis code is IN the manuscript -->
<!-- - Plus: Don't make all those tables and figures manually! :-) -->

## Output formats

- HTML - easy to share results on the web
- PDF - for manuscripts/reports (requires installing `latex`)
- Word - for editing with non-R collaborators, journals

## Templates

- Nicely formatted handouts / reports
- APA manuscripts using `papaja` (we'll get into this in depth)
- Specialized styles like PNAS or Cognitive Science
- Don't waste time reformatting - just change the template

## RMarkdown presentations

- If you want to go overboard, you can render slides from code too
- This is not always perfect, but it's great for course notes, especially teaching stats.
- This presentation also written in Rmarkdown!

## Workshop

Work through the handout accompanying these slides, which you can find at [http://bit.ly/rmarkdown-pdf](https://bit.ly/rmarkdown-pdf) and [http://bit.ly/rmarkdown-html](https://bit.ly/rmarkdown-html)

repo_name: libscie/rmarkdown-workshop

repo_language: HTML


text:
%% This BibTeX bibliography file was created using BibDesk.
%% http://bibdesk.sourceforge.net/

%% Created for Michael Frank at 2017-07-31 09:31:00 -0400

%% Saved with string encoding Unicode (UTF-8)

@article{nuijten2016,
	Author = {Nuijten, Mich{\`e}le B and Hartgerink, Chris HJ and van Assen, Marcel ALM and Epskamp, Sacha and Wicherts, Jelte M},
	Date-Added = {2017-07-25 01:33:07 +0000},
	Date-Modified = {2017-07-25 01:33:09 +0000},
	Journal = {Behavior research methods},
	Number = {4},
	Pages = {1205--1226},
	Publisher = {Springer},
	Title = {The prevalence of statistical reporting errors in psychology (1985--2013)},
	Volume = {48},
	Year = {2016}}

@book{xie2013,
	Author = {Xie, Yihui},
	Date-Added = {2015-11-25 22:42:30 +0000},
	Date-Modified = {2017-07-25 01:33:09 +0000},
	Publisher = {CRC Press},
	Title = {Dynamic Documents with R and knitr},
	Volume = {29},
	Year = {2013}}


text:
Version: 1.0

RestoreWorkspace: Default
SaveWorkspace: Default
AlwaysSaveHistory: Default

EnableCodeIndexing: Yes
UseSpacesForTab: Yes
NumSpacesForTab: 2
Encoding: UTF-8

RnwWeave: Sweave
LaTeX: pdfLaTeX


text:
---
title: "RMarkdown for writing reproducible scientific papers"
author: '[Mike Frank](mailto:mcfrank@stanford.edu) & [Chris Hartgerink](mailto:chris@libscie.org)'
date: '`r Sys.Date()`'
output:
  tufte::tufte_html:
    toc: yes
    toc_depth: 1
  tufte::tufte_handout:
    citation_package: natbib
    latex_engine: pdflatex
  tufte::tufte_book:
    citation_package: natbib
    latex_engine: pdflatex
link-citations: yes
bibliography: library.bib
---

```{r, echo=FALSE}
library(knitr)
opts_chunk$set(echo=TRUE,
               warning=FALSE, message=FALSE,
               cache=FALSE)
```

# Introduction

This document is a short tutorial on using RMarkdown to mix prose and code together for creating reproducible scientific documents.^[There is also a slidedeck that goes along with this handout available **[here](https://libscie.github.io/rmarkdown-workshop)**, which is worth looking at if you don't know what you're doing on this page and what to look at. Going through this document takes at most two hours, assuming you already know some basic `R` programming. If you find any errors and have a Github account, **[please suggest changes here](https://github.com/libscie/rmarkdown-workshop/edit/master/handout.Rmd)**. All **[content](https://github.com/libscie/rmarkdown-workshop)** is CC 0 licensed, so feel free to remix and reuse!]

The tutorial is based on documents that both Chris and Mike wrote independently (see [here](https://elifesciences.org/labs/cad57bcf/composing-reproducible-manuscripts-using-r-markdown) and [here](http://babieslearninglanguage.blogspot.com/2015/11/preventing-statistical-reporting-errors.html) if you're interested). In short: RMarkdown allows you to create documents that are compiled with code, producing your next scientific paper.^[Note: this is also possible for Python and other open-source data analysis languages, but we focus on R.]

Now we're together trying to help spread the word, because it can make writing manuscripts so much easier! We wrote this handout in RMarkdown as well (looks really sweet, no?).

## Who is this aimed at?

We aim this document at anyone writing manuscripts and using R, including those who...

1. ...collaborate with people who use Word
2. ...want to write complex equations
3. ...want to be able to change bibliography styles with less hassle
4. ...want to spend more time actually doing research!

## Why write reproducible papers?

Cool, thanks for sticking with us and reading up through here!

There are three reasons to write reproducible papers. To be right, to be reproducible, and to be efficient. There are more, but these are convincing to us. In more depth:

1. To avoid errors. Using an automated method for scraping APA-formatted stats out of PDFs, @nuijten2016 found that over 10% of p-values in published papers were inconsistent with the reported details of the statistical test, and 1.6% were what they called "grossly" inconsistent, e.g. difference between the p-value and the test statistic meant that one implied statistical significance and the other did not. Nearly half of all papers had errors in them.

2. To promote computational reproducibility. Computational reproducibility means that other people can take your data and get the same numbers that are in your paper. Even if you don't have errors, it can still be very hard to recover the numbers from published papers because of ambiguities in analysis. Creating a document that literally specifies where all the numbers come from in terms of code that operates over the data removes all this ambiguity.

3. To create spiffy documents that can be revised easily. This is actually a really big neglected one for us. At least one of us used to tweak tables and figures by hand constantly, leading to a major incentive *never to rerun analyses* because it would mean re-pasting and re-illustratoring all the numbers and figures in a paper. That's a bad thing! It means you have an incentive to be lazy and to avoid redoing your stuff. And you waste tons of time when you do. In contrast, with a reproducible document, you can just rerun with a tweak to the code. You can even specify what you want the figures and tables to look like before you're done with all the data collection (e.g., for purposes of preregistraion or a registered report).

## Learning goals

By the end of this class you should:

* Know what Markdown is and how the syntax works,
* See how to integrate code and data in RMarkdown,
* Understand the different output formats from RMarkdown and how to generate them, and
* Know about generating APA format files with `papaja` and bibtex.

# Getting Started

## Installation

Before we get started with running everything, make sure to have `R` installed (download [here](https://cran.r-project.org/)) and `Rstudio` (download [here](https://www.rstudio.com/products/rstudio/download/#download)). If you haven't yet, go do that first and we'll be here when you get back!

## Exercise

Great, you installed both `R` and `Rstudio`! Next up, making your first RMarkdown file.

Fire up Rstudio and create a new RMarkdown file. Don't worry about the settings, we'll get to that later.

```{r, echo = FALSE}
knitr::include_graphics('figures/newfile.png')
```

If you click on "Knit" (or hit `CTRL+SHIFT+K`) the RMarkdown file will run and generate all results and present you with a PDF file, HTML file, or a Word file. If RStudio requests you to install packages, click yes and see whether everything works to begin with.

We need that before we teach you more about RMarkdown. But you should feel good if you get here already, because honestly, you're about 80% of the way to being able to write basic RMarkdown files. It's _that_ easy.

# Structure of an RMarkdown file

An RMarkdown file contains several parts. Most essential are the header, the body text, and code chunks.

## Header

Headers in RMarkdown files contain some metadata about your document, which you can customize to your liking. Below is a simple example that purely states the title, author name(s), date^[Pro-tip: you can use the `Sys.Date()` function to have that use the current date when creating the document.], and output format.

```yaml
---
title: "Untitled"
author: "NAME"
date: "July 28, 2017"
output: html_document
---
```

For now, go ahead and set `html_document` to `word_document`, except if you have strong preferences for `HTML` or `PDF`.^[Note: to create PDF documents you also need a TeX installation. Don't know what that is? You probably don't have it then. More info below.]

## Body text

The body of the document is where you actually write your reports. This is primarily written in the Markdown format, which is explained in the [Markdown syntax](#markdown-syntax) section.

The beauty of RMarkdown is, however, that you can evaluate `R` code right in the text. To do this, you start inline code with \`r, type the code you want to run, and close it again with a \`. Usually, this key is below the escape (`ESC`) key  or next to the left SHIFT button.

For example, if you want to have the result of 48 times 35 in your text, you type \` r 48-35\`, which returns `r 48 - 35`. Please note that if you return a value with many decimals, it will also print these depending on your settings (for example, `r pi`).

## Code chunks

In the section above we introduced you to running code inside text, but often you need to take several steps in order to get to the result you need. And you don't want to do data cleaning in the text! This is why there are code chunks. A simple example is a code chunk loading packages.

First, insert a code chunk by going to `Code->Insert code chunk` or by pressing `CTRL+ALT+I`. Inside this code chunk you can then type for example, `library(ggplot2)` and create an object `x`.

```{r}
library(ggplot2)

x <- 1 + 1
```

If you do not want to have the contents of the code chunk to be put into your document, you include `echo=FALSE` at the start of the code chunk. We can now use the contents from the above code chunk to print results (e.g., $x=`r x`$).

These code chunks can contain whatever you need, including tables, and figures (which we will go into more later). Note that all code chunks regard the location of the RMarkdown as the working directory, so when you try to read in data use the relative path in.

## Exercises

These exercises are all about failure modes to RMarkdown. Go ahead and switch over to your new RMarkdown file.

1. Create a code chunk. In it, use `write.csv(USArrests, "USArrests.csv")` to write out some data to your hard drive. Subsequently, find that file on your computer. Where is it?

2. Load the `ggplot2` package (or any other that you use frequently) in a code chunk and regenerate the document. Now try to load some packages you've never heard of, like `adehabitatHS` or `QCA`. What happens?

## Solutions

1. RMarkdown files operate out of the directory in which they are located. If you read in data, it's important to write paths relatively starting from that "project root" directory, instead of absolute -- otherwise when you share the file the paths will all be wrong. Similarly, if you write out data they go in the root directory.

2. If you don't have packages installed, the knitting process will fail. How do you head this off?  We like to load all our packages at the top of the document so it's easy to know what you need to install to make it run; it's also easy for users to see what packages they need. Some folks `install.packages` *in the script*, though we don't advocate for that here.

# Markdown syntax

Markdown is one of the simplest document languages around, that is an open standard and can be converted into `.tex`, `.docx`, `.html`, `.pdf`, etc. This is the main workhorse of RMarkdown and is very powerful. You can [learn Markdown in five (!) minutes](https://learnxinyminutes.com/docs/markdown/) Other resources include [http://rmarkdown.rstudio.com/authoring_basics.html](), and [this cheat sheet](https://www.rstudio.com/wp-content/uploads/2015/02/rmarkdown-cheatsheet.pdf).

You can do some pretty cool tricks with Markdown, but these are the basics:

* It's easy to get `*italic*` or `**bold**`.
* You can get headings using `# heading1` for first level, `## heading2` for second-level, and `### heading3` for third level.
* Lists are delimited with `*` for each entry.
* You can write links by writing `[here's my link](http://foo.com)`.

If you want a more extensive description of all the potential of Markdown, [this introduction to Markdown](https://daringfireball.net/projects/markdown/) is highly detailed.

## Exercises

Swap over to your new sample markdown.

1. Outlining using headings is a really great way to keep things organized! Try making a bunch of headings, and then recompiling your document.
2. Add a table of contents. This will involve going to the header of the document (the `YAML`), and adding some options to the `html document` bit. You want it to look like this (indentation must to be correct):

```yaml
output:
  html_document:
    toc: true
```

Now recompile. Looks nice, right?^[Pro-tip: you can specify how deep the TOC should go by adding `toc_depth: 2` to go two levels deep]

3. Try adding another option: `toc_float: true`. Recompile -- super cool. There are plenty more great output options that you can modify. [Here is a link to the documentation.](http://rmarkdown.rstudio.com/html_document_format.html)

#  Headers, Tables, and Graphs

## Headers

We're going to want more libraries loaded (for now we're loading them inline).

```{r}
library(knitr)
library(ggplot2)
library(broom)
library(devtools)
```

We often also add `chunk options` to each code chunk so that, for example:

- code does or doesn't display inline (`echo` setting)
- figures are shown at various sizes (`fig.width` and `fig.height` settings)
- warnings and messages are suppressed (`warning` and `message` settings)
- computations are cached (`cache` setting)

There are many others available as well. Caching can be very helpful for large files, but can also cause problems when there are external dependencies that change. An example that is useful for manuscripts is:

```{r eval=FALSE}
opts_chunk$set(fig.width=8, fig.height=5,
               echo=TRUE,
               warning=FALSE, message=FALSE,
               cache=TRUE)
```

## Graphs

It's really easy to include graphs, like this one. (Using the `mtcars` dataset that comes with `ggplot2`).

```{r}
qplot(hp, mpg, col = factor(cyl), data = mtcars)
```

All you have to do is make the plot and it will render straight into the text.

External graphics can also be included, as follows:

```{r eval = FALSE}
knitr::include_graphics("path/to/file")
```

## Tables

There are many ways to make good-looking tables using RMarkdown, depending on your display purpose.

- The `knitr` package (which powers RMarkdown) comes with the `kable` function. It's versatile and makes perfectly reasonable tables. It also has a `digits` argument for controlling rounding.
- For HTML tables, there is the `DT` package, which provides `datatable` -- these are pretty and interactive javascript-based tables that you can click on and search in. Not great for static documents though.
- For APA manuscripts, it can also be helpful to use the `xtable` package, which creates very flexible LaTeX tables. These can be tricky to get right but they are completely customizable provided you want to google around and learn a bit about tex.

We recommend starting with `kable`:

```{r}
kable(head(mtcars), digits = 1)
```

## Statistics

It's also really easy to include statistical tests of various types.

For this, an option is the `broom` package, which formats the outputs of various tests really nicely. Paired with knitr's `kable` you can make very simple tables in just a few lines of code.

```{r}
mod <- lm(mpg ~ hp + cyl, data = mtcars)
kable(tidy(mod), digits = 3)
```

Of course, cleaning these up can take some work. For example, we'd need to rename a bunch of fields to make this table have the labels we wanted (e.g., to turn `hp` into `Horsepower`).

We often need APA-formatted statistics. We can compute them first, and then print them inline.

```{r}
ts <- with(mtcars,t.test(hp[cyl==4], hp[cyl==6]))
```

> There's a statistically-significant difference in horsepower for 4- and 6-cylinder cars  ($t(`r round(ts$parameter,2)`) = `r round(ts$statistic,2)`$, $p = `r round(ts$p.value,3)`$).

To insert these stats inline I wrote e.g. `round(ts$parameter, 2)` inside an inline code block.^[APA would require omission of the leading zero. `papaja::printp()` will let you do that, see below.]

Note that rounding can occasionally get you in trouble here, because it's very easy to have an output of $p = 0$ when in fact $p$ can never be exactly equal to 0. Nonetheless, this can help you prevent rounding errors and the wrath of `statcheck`.

## Exercises

1. Using the `mtcars` dataset, insert a table and a graph of your choice into the document.^[If you're feeling uninspired, try `hist(mtcars$mpg)`.]

# Writing APA-format papers

(Thanks to [Frederick Aust](http://github.com/crsh) for contributing this section!)

The end-game of reproducible research is to knit your entire paper. We'll focus on APA-style writeups. Managing APA format is a pain in the best of times. Isn't it nice to get it done for you?

We're going to use the `papaja` package. `papaja` is a R-package including a R Markdown template that can be used to produce documents that adhere to the American Psychological Association (APA) manuscript guidelines (6th Edition).

## Software requirements

To use `papaja`, make sure you are using the latest versions of R and RStudio. If you want to create PDF- in addition to DOCX-files you need **[TeX](http://de.wikipedia.org/wiki/TeX) 2013 or later**. Try [MikTeX](http://miktex.org/) for Windows, [MacTeX](https://tug.org/mactex/) for Mac, or [TeX Live](http://www.tug.org/texlive/) for Linux. Some Linux users may need a few additional TeX packages for the LaTeX document class `apa6` to work.^[For Ubuntu, we suggest running: `sudo apt-get install texlive texlive-publishers texlive-fonts-extra texlive-latex-extra texlive-humanities lmodern`.]

## Installing `papaja`

`papaja` has not yet been released on CRAN but you can install it from GitHub.

```{r install_papapja, eval = FALSE}
# Install devtools package if necessary
if(!"devtools" %in% rownames(installed.packages())) install.packages("devtools")

# Install papaja
devtools::install_github("crsh/papaja")
```

## Creating a document

The APA manuscript template should now be available through the RStudio menus when creating a new R Markdown file.

```{r template-selection, echo = FALSE, fig.cap = "papaja's APA6 template is available through the RStudio menues."}
knitr::include_graphics("figures/template_selection.png")
```

When you click RStudio's *Knit* button `papaja`, `rmarkdown,` and `knitr` work together to create an APA conform manuscript that includes both your manuscript text and the results of any embedded R code.

```{r knit-button, echo = FALSE, fig.cap = "The *Knit* button in the RStudio."}
knitr::include_graphics("figures/knitting.png")
```

Note, if you don't have TeX installed on your computer, or if you would like to create a Word document replace `output: papaja::apa6_pdf` with `output: papaja::apa6_word` in the document YAML header.

`papaja` provides some rendering options that only work if you use `output: papaja::apa6_pdf`.
`figsintext` indicates whether figures and tables should be included at the end of the document---as required by APA guidelines---or rendered in the body of the document.
If `figurelist`, `tablelist`, or `footnotelist` are set to `yes` a list of figure captions, table captions, or footnotes is given following the reference section.
`lineno` indicates whether lines should be continuously numbered through out the manuscript.

## Reporting statistical analyses

`apa_print()` facilitates reporting of statistical analyses.
The function formats the contents of R objects and produces readily reportable text.

```{r eval=FALSE}
recall_anova <- afex::aov_car(
  Recall ~ (Task * Valence * Dosage) + Error(Subject/(Task * Valence)) + Dosage
  , data = mixed_data
  , type = 3
)
recall_anova_results <- apa_print(recall_anova, es = "pes")
recall_anova_results_p <- apa_print(recall_anova, es = "pes", in_paren = TRUE)
```

Now, you can report the results of your analyses like so:

> Item valence (\` r anova_results_p$full$Valence\`) and the task affected recall performance, \` r anova_results$full$Task\`; the dosage, however, had no effect on recall, \` r anova_results$full$Dosage\`. There was no significant interaction.

`apa_print()` also creates reportable tables---in this case a complete ANOVA table.
You can include the table into the document by passing `recall_anova_results$table` to `apa_table()`.
Remeber to include the `results = "asis"` argument in the chunk options of the chunk that generates the table.

```{r eval=FALSE}
apa_table(
  recall_anova_results$table
  , align = c("lrcrrr")
  , caption = "ANOVA table for the analyis of the example data set."
  , note = "This is a table created using R and papaja."
)
```

## Cross-referencing

`papaja` enables the use of `bookdown` cross-referencing syntax as detailed in the [bookdown documentation](https://bookdown.org/yihui/bookdown/cross-references.html).
Generally, a cross-reference to a figure, table, or document section can be done by using the syntax `\@ref(label)`.
If you set a figure caption in a code chunk via the chunk option `fig.cap = "This is my figure caption."`, the label for that figure is based on the label of the code chunk, e.g., if the chunk label is `foo`, the figure label will be `fig:foo`.
If you used `knitr::kable()` or `apa_table()` to create a table, the label for that table is, again, based on the label of the code chunk, e.g., if the chunk label is `foo`, the figure label will be `tab:foo`.

## Bibiographic management

It's also possible to include references using `bibtex`, by using `@ref` syntax. An option for managing references is [bibdesk](http://bibdesk.sourceforge.net/), which integrates with google scholar.^[But many other options are possible.]

With a bibtex file included, you can refer to papers. As an example, `@nuijten2016` results in the in text citation "@nuijten2016", or cite them parenthetically with `[@nuijten2016]` [@nuijten2016]. Take a look at the `papaja` APA example to see how this works.

`citr` is an R package that provides an easy-to-use [RStudio addin](https://rstudio.github.io/rstudioaddins/) that facilitates inserting citations.
The addin will automatically look up the Bib(La)TeX-file(s) specified in the YAML front matter.
The references for the inserted citations are automatically added to the documents reference section.

<!-- # ```{r citr-gif, echo = FALSE, fig.align = "center", fig.cap = "Demonstration of the RStudio addin from the `citr` package that inserts R Markdown citations."} -->
<!-- # knitr::include_graphics("figures/addin_demo.gif") -->
<!-- # ``` -->

Once `citr` is installed (`install.packages("citr")`) and you have restarted your R session, the addin appears in the menus and you can define a [keyboard shortcut](https://rstudio.github.io/rstudioaddins/#keyboard-shorcuts) to call the addin.

## Exercise

Make sure you've got `papaja`, then open a new template file. Compile this document, and look at how awesome it is. (To compile you need `texlive`, a library for compiling markdown to PDF, so you may need to wait and install this later if it's not working).

Try pasting in your figure and table from your other RMarkdown (don't forget any libraries you need to make it compile). Presto, ready to submit!

For a bit more on `papaja`, check out **[this guide](https://rpubs.com/YaRrr/papaja_guide)**.

# Further Frontiers

## Other dissemination methods

We didn't spend as much time on it here, but one of the biggest strengths of RMarkdown is how you can easily switch between formats. For example, we made **[our slides in RMarkdown](https://libscie.github.io/rmarkdown-workshop)** using `revealjs` (`ioslides` is also a good option).

We also like to share HTML RMarkdown reports with collaborators using the [RPubs service](http://rpubs.com) or hosting of your own choice. It's incredibly easy to share your work publicly this way -- you just push the "publish" button in the upper right hand corner of the RStudio viewer window. Then you set up an account, and you are on your way. We find this is a great method for sending analysis writeups -- no more pasting figures into email! Hosting HTML files on your own page is also easy if you know how that works.

And of course because not everyone uses R, you can simply click on the knit options at the top of the code window to switch to a Word output format. Then your collaborators can edit the text in Word (or upload to Google docs) and you can re-merge the changes with your reproducible code. This isn't a perfect workflow yet, but it's not too bad.

## Computational reproducibility concerns

Once you provide code and data for your RMarkdown, you are most of the way to full computational reproducibility. Other people should be able to get the same numbers as you for your paper!

But there's still one wrinkle. What if you use linear mixed effect models from `lme4` and then the good people developing that package make it better -- but that changes your numbers? Package versioning (and versioning on `R` itself) is a real concern. To combat this issue, there are a number of tools out there.

* The `packrat` package is a solution for package versioning for `R`. It downloads local copies of all your packages, and that can ensure that you have all the right stuff to distribute with your work.^[We've found that this package is a bit tricky to use so we don't always recommend it, but it may improve in future.]
* Some other groups are using Docker, a system for making virtual machines that have everything for your project inside them and can be unpacked on other machines to reproduce your *exact* environment. We haven't worked with these but they seem like a good option for full reproducibility.
* The `checkpoint` package allows you to install packages exactly as they were on CRAN (the main repository for packages), so you can "freeze" your package versions ([more info here](https://cran.r-project.org/web/packages/checkpoint/index.html)).

If you don't want to pursue these heavier-weight options, one simple thing you *can* do is end your RMarkdown with a printout of all the packages you used. Do this by running `sessionInfo`.

```{r}
sessionInfo()
```