30575-hard-bitwisexor

Back

Not good, it's the first idea that came to my mind.

// string to array, '101' => ['1', '0', '1']
type StringArray<S, R extends string[] = []> =
  S extends `${infer A}${infer Rest}`
    ? StringArray<Rest, [...R, A]>
    : R

// Receive Two string[] to get the result
type GetResult<
  T1 extends string[],
  T2 extends string[],
  R extends string = ''
> =
  T1 extends [...infer Rest1 extends string[], infer A1 extends string]
    ? T2 extends [...infer Rest2 extends string[], infer A2 extends string]
      ? GetResult<Rest1, Rest2, `${A1 extends A2 ? 0 : 1}${R}`>
      : GetResult<Rest1, [], `${A1}${R}`>
    : T2['length'] extends 0
      ? R
      : GetResult<T2, [], R>

// Trun S1, S2 to array of string and pass to GetResult
// Because it's easier to get the last element out of an array
type BitwiseXOR<
  S1 extends string,
  S2 extends string
> = GetResult<StringArray<S1>, StringArray<S2>>

Solution by drylint #34220

type BitwiseXOR<A extends string, B extends string, X extends string = ''>
  = `${A}^${B}` extends `${infer C}1^${infer D}0` | `${infer C}0^${infer D}1` ? BitwiseXOR<C, D, `1${X}`>
  : `${A}^${B}` extends `${infer C}1^${infer D}1` | `${infer C}0^${infer D}0` ? BitwiseXOR<C, D, `0${X}`>
  : `${A}${B}${X}`

Playground

Solution by teamchong #32992

type BitwiseXOR<S1 extends string, S2 extends string> = ReverseString<
  Xor<ReverseString<S1>, ReverseString<S2>>
>;

type ReverseString<S extends string> = S extends `${infer Char}${infer Others}`
  ? `${ReverseString<Others>}${Char}`
  : "";
  
type Xor<
  S1 extends string,
  S2 extends string
> = S1 extends `${infer L}${infer Others}`
  ? S2 extends `${infer L1}${infer Others1}`
    ? L extends L1
      ? `0${Xor<Others, Others1>}`
      : `1${Xor<Others, Others1>}`
    : `1${Xor<Others, "">}`
  : S2 extends `${infer L1}${infer Others1}`
  ? `1${Xor<"", Others1>}`
  : "";

Solution by Vampirelee #32716

type Reverse<S extends string> = S extends `${infer First}${infer Rest}` ? `${Reverse<Rest>}${First}` : ''

type GetLastAndRest<S extends string, _S extends string = Reverse<S>>
  = _S extends `${infer Last extends string}${infer Rest extends string}`
    ? { Last: Last, Rest: Reverse<Rest> }
    : { Last: '', Rest: '' }

type XOR<S1 extends string, S2 extends string> = S1 extends S2 ? '0' : '1'

type BitwiseXOR<
  S1 extends string,
  S2 extends string,
  _S1 extends { Last: string, Rest: string } = GetLastAndRest<S1>,
  _S2 extends { Last: string, Rest: string } = GetLastAndRest<S2>
> = `${ _S1['Rest'] }${ _S2['Rest'] }` extends ''
    ? `${XOR<_S1['Last'], _S2['Last']>}`
    : `${BitwiseXOR<_S1['Rest'], _S2['Rest']>}${XOR<_S1['Last'], _S2['Last']>}`

Solution by lvjiaxuan #32481

type ReverseString<S extends string> = S extends `${infer First}${infer Rest}`
  ? `${ReverseString<Rest>}${First}`
  : "";
type XOR<T extends string, U extends string> = T extends U ? "0" : "1";
type BitwiseXOR<
  S1 extends string,
  S2 extends string
> = ReverseString<S1> extends `${infer F1}${infer R1}`
  ? ReverseString<S2> extends `${infer F2}${infer R2}`
    ? `${BitwiseXOR<ReverseString<R1>, ReverseString<R2>>}${XOR<F1, F2>}`
    : S1
  : S2;

Solution by vangie #32338

type XORSingle<A extends string, B extends string> = A extends B ?  '0' : '1';
type Revert<S extends string> = S extends `${infer Start}${infer End}` ? `${Revert<End>}${Start}` : '';

type IterateXOR<S1 extends string, S2 extends string> = S1 extends `${infer Start1}${infer End1}` ? 
S2 extends `${infer Start2}${infer End2}` ? `${IterateXOR<End1, End2>}${XORSingle<Start1, Start2>}` : 
S1 : S2 extends `${infer Start2}${infer End2}` ? S2 : '';

type BitwiseXOR<S1 extends string, S2 extends string> = IterateXOR<Revert<S1>, Revert<S2>>;

Solution by Karamuto #31256

type BitwiseXOR<S1 extends string, S2 extends string> = [S1, S2] extends [
  `${infer S1Body}${'0' | '1'}`,
  `${infer S2Body}${'0' | '1'}`,
]
  ? `${BitwiseXOR<S1Body, S2Body>}${[S1, S2] extends
      | [`${string}0`, `${string}0`]
      | [`${string}1`, `${string}1`]
      ? '0'
      : '1'}`
  : `${S1}${S2}`;

Alternative:

type RevertString<S extends string> = S extends `${infer S0}${infer SRest}`
  ? `${RevertString<SRest>}${S0}`
  : '';

type BitwiseXOR<S1 extends string, S2 extends string> = BitwiseXOR.XORReverted<
  RevertString<S1>,
  RevertString<S2>
>;
namespace BitwiseXOR {
  export type XORReverted<S1 extends string, S2 extends string, R extends string = ''> = [
    S1,
    S2,
  ] extends [`${infer S10}${infer S1Rest}`, `${infer S20}${infer S2Rest}`]
    ? XORReverted<S1Rest, S2Rest, `${S10 extends S20 ? '0' : '1'}${R}`>
    : `${RevertString<`${S1}${S2}`>}${R}`;
}

Solution by BOCbMOU #31036

// 解答をここに記入

type ReversedStr<S> = S extends `${infer F}${infer Rest}` ? `${ReversedStr<Rest>}${F}` : ""

type XOR<X, Y> = [X, Y] extends ["0", "0"] | ["1", "1"] ? "0" : "1"

type InnerBitwiseXOR<S1 extends string, S2 extends string> = [S1, S2] extends [`${infer F1}${infer R1}`, `${infer F2}${infer R2}`] ? `${XOR<F1, F2>}${InnerBitwiseXOR<R1, R2>}` : `${S1}${S2}`

type BitwiseXOR<S1 extends string, S2 extends string> = ReversedStr<InnerBitwiseXOR<ReversedStr<S1>, ReversedStr<S2>>>

桁数が S1 と S2 で違う場合にも簡潔に処理をするため、一旦文字列を反転させてから XOR の処理をしていきます。そして、最終結果も反転させることで元に戻します。

type InnerBitwiseXOR<S1 extends string, S2 extends string> = [S1, S2] extends [`${infer F1}${infer R1}`, `${infer F2}${infer R2}`] ? `${XOR<F1, F2>}${InnerBitwiseXOR<R1, R2>}` : `${S1}${S2}`

において、再帰終了条件に単に [S1, S2] extends [${infer F1}${infer R1}, ${infer F2}${infer R2}] の失敗を設定し、 ${S1}${S2} を返すようにしているのは、

Solution by Kakeru-Miyazaki #30982

type FillZero<S1 extends string, S2 extends string, _Result1 extends string = ``, _Result2 extends string = ``> =
  `` extends S1 & S2 ? [_Result1, _Result2] /*return*/ :
  FillZero<
    S1 extends `${any}${infer R}` ? R : ``,
    S2 extends `${any}${infer R}` ? R : ``,
    S1 extends `${infer F}${any}` ? `${_Result1}${F}` : `0${_Result1}`,
    S2 extends `${infer F}${any}` ? `${_Result2}${F}` : `0${_Result2}`
  >;

type BitwiseXOR<S1 extends string, S2 extends string, _FZS extends [string, string] = FillZero<S1, S2>> =
  _FZS[0] extends `${infer F1}${infer R1}` ?
  _FZS[1] extends `${infer F2}${infer R2}` ?
  `${[F1 & F2] extends [never] ? 1 : 0}${BitwiseXOR<R1, R2, [R1, R2]>}` :
  `` :
  `` /*pop*/;

Solution by E-uler #30980

type BitwiseXOR<S1 extends string, S2 extends string> = 
  S1 extends '' ? S2 : S2 extends '' ? S1 
: S1 extends `${infer P1}0`
   ? S2 extends `${infer P2}0` 
      ? `${BitwiseXOR<P1,P2>}0` 
      : (S2 extends `${infer P2}1` ? `${BitwiseXOR<P1,P2>}1` : never)
: S1 extends `${infer P1}1` 
  ? S2 extends `${infer P2}0` 
    ? `${BitwiseXOR<P1,P2>}1` 
    : (S2 extends `${infer P2}1` ? `${BitwiseXOR<P1,P2>}0` : never)
: never

Solution by genaby #30696

type BitwiseXOR<S1 extends string, S2 extends string> = S1 extends ''
    ? S2
    : S2 extends ''
      ? S1
      : [S1, S2] extends [`${infer Rest1}${'0' | '1'}`, `${infer Rest2}${'0' | '1'}`]
        ? `${BitwiseXOR<Rest1, Rest2>}${XorLowestBit<S1, S2>}`
        : never
type XorLowestBit<S1 extends string, S2 extends string> = [S1, S2] extends [`${any}0`, `${any}1`] | [`${any}1`, `${any}0`] ? '1' : '0'

Solution by Sun79 #30589

type MakePrefix<
  S extends string, 
  P extends string = ''
> = 
  S extends `${string}${infer R}`?
    MakePrefix<R,`${P}0`>
    :P

type Pad<S1 extends string,S2 extends string> = 
  [S1,S2]extends [`${string}${infer RS1}`,`${string}${infer RS2}`]?
    Pad<RS1,RS2>: [MakePrefix<S2>,MakePrefix<S1>]

type _XOR<
  S1 extends string,
  S2 extends string,
  R extends string = ''
> =  
[S1,S2] extends [`${infer F1}${infer R1}`,`${infer F2}${infer R2}`]?
  _XOR<R1,R2,`${R}${F1 extends F2?'0':'1'}`>
  :R


type BitwiseXOR<
  S1 extends string,
  S2 extends string
> = 
  Pad<S1,S2> extends [infer P1 extends string,infer P2 extends string]?
    _XOR<`${P1}${S1}`,`${P2}${S2}`>
    :never

Solution by jiangshanmeta #30577